
/**
 * 通常情况下我们会有一个叫做音频上下文的变量，
 * 表示由链接在一起的音频模块构建的音频处理图
 * 每个模块由一个 AudioNode 表示。音频上下文控制它包含的节点的创建和音频处理或解码的执行。 
 * 对于 Audio API 本身而言，这是起点，任何类型的 Web 音频 API应用程序都在使用此音频上下文。
*/

import { Button, Slider } from 'antd';
import { useEffect, useRef, useState } from 'react';

const mp3Url = '/cyberpunk.mp3';

const GainNodeDemo = () => {
    const [volume, setVolume] = useState(0.5);
    const [paused, setPaused] = useState(true);
    const audioRef = useRef<HTMLAudioElement>();
    const gainNodeRef = useRef<GainNode>();
    const audioContextRef = useRef<AudioContext>();

    useEffect(() => {
        return () => {
            audioRef.current?.pause();
            audioContextRef.current?.close();
        }
    }, []);

    const handleClick = () => {
        const audio = audioRef.current;
        if (audio) {
            audio.paused ? audio.play() : audio.pause();
            setPaused(audio.paused);
        } else {
            const audio = document.createElement('audio');
            audioRef.current = audio;
            setPaused(false);
            if (!audioContextRef.current) {
                audioContextRef.current = new AudioContext();
            }
            if (!gainNodeRef.current) {
                gainNodeRef.current = audioContextRef.current.createGain();
            }
            const audioContext = audioContextRef.current;
            const source = audioContext.createMediaElementSource(audio);
            source.connect(gainNodeRef.current);        // 连接 GainNode
            gainNodeRef.current.gain.setTargetAtTime(
                volume, audioContextRef.current.currentTime, 0.01
            );
            gainNodeRef.current.connect(audioContext.destination);

            audio.loop = true;
            audio.src = mp3Url;
            audio.play();   // 播放
        }
    }

    const changeVolume = (value: number) => {
        setVolume(value);
        console.log('volume value: ', value);
        // 处理音频
        if (!paused && gainNodeRef.current && audioContextRef.current) {
            gainNodeRef.current.gain.setTargetAtTime(
                /**  从原来的音量过渡到对应的 value 音量，过度时长：0.01s */
                value, audioContextRef.current.currentTime, 0.01
            );
        }
    }

    return (
        <div style={{ width: 240 }}>
            <Button onClick={handleClick}>{ paused ? '播放' : '暂停' }</Button>
            <br />
            <Slider step={0.01} min={0} max={1} value={volume} onChange={changeVolume} />
            音量大小：{(volume * 100).toFixed(2)}%
        </div>
    );
};

export default GainNodeDemo;
